<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    body{
      background: #00092C;
    }
  </style>
</head>
<body>
<div id="mountNode"></div>
</body>
<script src="./test/dagre.js"></script>
<script src="./test/g6.js"></script>
<script>
  /**
   * node 特殊属性
   */
  const nodeExtraAttrs = {
    begin: {
      fill: "#9FD4FB",
    },
    end: {
      fill: "#C2E999",
    },
    end1: {
      fill: "#FC5D73",
    },
  };

  const data = {
    nodes: [
      {
        id: "1",
        label: "主节点",
        type: "begin",
        level:1,
        width:150,
        height:150,
        x:-75,
        y:-75,
        img:"./test/screenTopo1.png",
      },
      {
        id: "2",
        level:2,
        label: "交易创建",
        img:"./test/screenTopo2.png",
      },
      {
        id: "3",
        level:2,
        label: "请求回放3",
        img:"./test/screenTopo2.png",
      },
      {
        id: "4",
        level:2,
        img:"./test/screenTopo2.png",
        label: "请求回放4"
      },
      {
        id: "5",
        level:2,
        img:"./test/screenTopo2.png",
        label: "请求回放5"
      },
      {
        id: "6",
        level:2,
        img:"./test/screenTopo2.png",
        label: "请求回放6"
      },{
        id: "2-1",
        label: "节点",
        level:3,
        type: "end",
        img:"./test/screenTopo3.png",
      },{
        id: "2-2",
        level:3,
        img:"./test/screenTopo3.png",
        label: "节点",
        type: "end"
      },{
        id: "2-3",
        level:3,
        img:"./test/screenTopo3.png",
        label: "节点",
        type: "end"
      },{
        id: "2-4",
        level:3,
        img:"./test/screenTopo3.png",
        label: "节点",
        type: "end"
      },{
        id: "2-5",
        level:3,
        img:"./test/screenTopo3.png",
        label: "节点",
        type: "end"
      },{
        id: "3-1",
        level:4,
        img:"./test/screenTopo4.png",
        label: "节点",
        type: "end1"
      },{
        id: "3-2",
        level:4,
        img:"./test/screenTopo4.png",
        label: "节点",
        type: "end1"
      },{
        id: "3-3",
        level:4,
        img:"./test/screenTopo4.png",
        label: "节点",
        type: "end1"
      },{
        id: "3-4",
        level:4,
        img:"./test/screenTopo4.png",
        label: "节点",
        type: "end1"
      },{
        id: "3-5",
        level:4,
        img:"./test/screenTopo4.png",
        label: "节点",
        type: "end1"
      },{
        id: "3-6",
        level:4,
        img:"./test/screenTopo4.png",
        label: "节点",
        type: "end1"
      },{
        id: "3-7",
        level:4,
        img:"./test/screenTopo4.png",
        label: "节点",
        type: "end1"
      },{
        id: "3-8",
        level:4,
        img:"./test/screenTopo4.png",
        label: "节点",
        type: "end1"
      }
    ],
    edges: [
      {
        source: "1",
        target: "2",
      },
      {
        source: "1",
        target: "3"
      },
      {
        source: "1",
        target: "4"
      },
      {
        source: "1",
        target: "5"
      },
      {
        source: "1",
        target: "6"
      },
      {
        source: "3",
        target: "2-1"
      },{
        source: "6",
        target: "2-2"
      },{
        source: "6",
        target: "2-3"
      },{
        source: "5",
        target: "2-4"
      },{
        source: "5",
        target: "2-5"
      },
      {
        source: "2-1",
        target: "3-1"
      },{
        source: "2-1",
        target: "3-2"
      },{
        source: "2-1",
        target: "3-3"
      },{
        source: "2-2",
        target: "3-4"
      },{
        source: "2-2",
        target: "3-5"
      },{
        source: "2-4",
        target: "3-6"
      },{
        source: "2-4",
        target: "3-7"
      },{
        source: "2-4",
        target: "3-8"
      }
    ]
  };

  /**
   * 自定义节点
   */
  G6.registerNode(
    "rect-node",
    {
      drawShape: function drawShape(cfg, group) {
        let width=70,height=60,x=-35,y=100;
        if(cfg.id==1){
          width=180;
          height=150;
          x=-90;
          y=-30;
        }
        var rect = group.addShape("image", {
          attrs: {
            x: x,
            y: y,
            width: width,
            height: height,
            img: cfg.img,
            radius: 4,
            fill: "#FFD591",
            fillOpacity: 1,
            ...nodeExtraAttrs[cfg.type]
          }
        });
        return rect;
      },
      getAnchorPoints: function getAnchorPoints(cfg) {
        console.log(cfg,'point');
        if(cfg.level==1){
          return [[0.5,0], [0.5, 1]];
        }
        if(cfg.level==2){
          return [[0.5,0.8], [0.5, 1]];
        }
        if(cfg.level==3){
          return [[0.5,0.8], [0.5, 1]];
        }
        if(cfg.level==4){
          return [[0.5,0], [0.5, 1]];
        }
      }
    },
    "single-shape"
  );

  /**
   * 自定义带箭头的贝塞尔曲线 edge
   */
  G6.registerEdge("line-with-point", {
    itemType: "edge",
    draw: function draw(cfg, group) {
      const startPoint = cfg.startPoint;
      const endPoint = cfg.endPoint;
      const centerPoint = {
        x: (startPoint.x + endPoint.x),
        y: (startPoint.y + endPoint.y)
      };
      // 控制点坐标
      const controlPoint = {
        x: (startPoint.x + centerPoint.x) / 2,
        y: startPoint.y
      };

      // console.log(cfg, startPoint, endPoint);

      // 为了更好的展示效果, 对称贝塞尔曲线需要连到箭头根部
      const path = group.addShape("path", {
        attrs: {
          path: [
            ["M", startPoint.x, startPoint.y],
            [
              "Q",
              controlPoint.x + 8,
              controlPoint.y,
              centerPoint.x,
              centerPoint.y
            ],
            ["T", endPoint.x - 8, endPoint.y],
            ["L", endPoint.x, endPoint.y]
          ],
          stroke: "#ccc",
          lineWidth: 1,
          endArrow: {
            path: "M 4,0 L -4,-4 L -4,4 Z",
            d: 44
          },
          startArrow: {
            path: "M 4,0 L -4,-4 L -4,4 Z",
            d: 44
          },
        }
      });
      // 计算贝塞尔曲线上的中心点
      // 参考资料 https://stackoverflow.com/questions/54216448/how-to-find-a-middle-point-of-a-beizer-curve
      // const lineCenterPoint = {
      //   x:
      //     (1 / 8) * startPoint.x +
      //     (3 / 8) * (controlPoint.x + 8) +
      //     (3 / 8) * centerPoint.x +
      //     (1 / 8) * (endPoint.x - 8),
      //   y:
      //     (1 / 8) * startPoint.y +
      //     (3 / 8) * controlPoint.y +
      //     (3 / 8) * centerPoint.y +
      //     (1 / 8) * endPoint.y
      // };

      // 在贝塞尔曲线中心点上添加圆形
      const { source, target } = cfg;
      group.addShape("circle", {
        attrs: {
          id: `statusNode${source}-${target}`,
          r: 6,
          x: centerPoint.x,
          y: centerPoint.y,
          fill: cfg.active ? "#AB83E4" : "#ccc"
        }
      });

      return path;
    }
  });

  const g = new dagre.graphlib.Graph();
  g.setDefaultEdgeLabel(function() { return {}; });
  g.setGraph({ rankdir: 'TB' });

  data.nodes.forEach(node => {
    g.setNode(node.id + '', { width: 80, height: 50 });
  });

  data.edges.forEach(edge => {
    edge.source = edge.source + '';
    edge.target = edge.target + '';
    g.setEdge(edge.source, edge.target);
  });
  dagre.layout(g);

  let coord;
  g.nodes().forEach((node, i) => {
    if(i==0){
      coord = g.node(node);
      // console.log(coord);
      data.nodes[i].x = coord.x+200;
      data.nodes[i].y = coord.y;
    }else{
      coord = g.node(node);
      data.nodes[i].x = coord.x;
      data.nodes[i].y = coord.y+100;
    }
  });
  g.edges().forEach((edge, i) => {
    coord = g.edge(edge);
    const startPoint = coord.points[0];
    const endPoint = coord.points[coord.points.length - 1];
    data.edges[i].startPoint = startPoint;
    data.edges[i].endPoint = endPoint;
    data.edges[i].controlPoints = coord.points.slice(
      1,
      coord.points.length - 1
    );
  });

  const graph = new G6.Graph({
    container: "mountNode",
    width: 2000,
    height: 800,

    defaultNode: {
      shape: "rect-node",

      labelCfg: {
        style: {
          fill: "#fff",
          fontSize: 14,
        }
      }
    },
    defaultEdge: {
      // shape: "line-with-point",
      shape: "line-point",
      style: {
        endArrow: false,
        // startArrow: true,
        lineWidth: 2,
        stroke: "#6EFE5E"
      }
    }
  });

  graph.data(data);
  graph.render();

  graph.on('edge:mouseover', evt => {
    const { target } = evt
    const type = target.get('type')
    // console.log(type);
    if(type === 'circle') {
      // 点击边上的circle
      alert('你点击的是边上的圆点')
    }
  })
  graph.on('mouseover', evt => {
    const { target } = evt
    const type = target.get('type')
    // console.log(type);
    if(type === 'circle') {
      // 点击边上的circle
      alert('你点击的是边上的圆点')
    }
  })
</script>
</html>
